package org.fuys.coder.application;

import org.fuys.coder.common.constants.RedisConstants;
import org.fuys.coder.common.entity.Pair;
import org.fuys.coder.common.entity.Result;
import org.fuys.coder.domain.config.service.impl.CoderRecommendConfig;
import org.fuys.coder.common.constants.ResultMessageConstants;
import org.fuys.coder.common.holder.CategoryVOHolder;
import org.fuys.coder.common.holder.UserHolder;
import org.fuys.coder.domain.substance.service.repo.ISubstanceService;
import org.fuys.coder.infrastructure.util.RedisUtil;
import org.fuys.coder.domain.category.model.vo.CategoryVO;
import org.fuys.coder.domain.rank.service.IHotRankService;
import org.fuys.coder.domain.recommend.service.IRecommendService;
import org.fuys.coder.domain.substance.model.vo.SubstanceVO;
import org.springframework.util.ObjectUtils;
import org.springframework.web.bind.annotation.GetMapping;
import org.springframework.web.bind.annotation.PostMapping;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RestController;

import javax.annotation.Resource;
import java.util.ArrayList;
import java.util.HashSet;
import java.util.List;
import java.util.Set;

/**
 * @projectName: fuys-low-coder
 * @package: org.fuys.coder.application
 * @className: RecommendController
 * @author: WangJing
 * @description: 推荐相关的应用层
 * @date: 2024/6/25 16:09
 * @version: 1.0
 */
@RestController
@RequestMapping("/fuyscoder/recommend")
public class RecommendController {

    @Resource
    private IRecommendService recommendService;

    @Resource
    private ISubstanceService substanceService;

//    @Resource
//    private RedisUtil redisUtil;

    @Resource
    private IHotRankService hotRankService;

    @Resource
    private CoderRecommendConfig config;


    @GetMapping("/hot")
    public Result hotRank(){
        hotRankService.hotRank();
        final List<SubstanceVO> hotSubstance = hotRankService.getHotSubstance();
        if(ObjectUtils.isEmpty(hotSubstance)){
            return Result.error(ResultMessageConstants.RECOMMEND_EMPTY);
        }
        return Result.ok().data(hotSubstance);
    }

    //用于长时间未登录 或者是新用户的推荐内容接口
    //注意 此接口路径不被拦截器拦截
    @GetMapping("/default")
    public Result defaultRecommend(){
        //正因为是默认的推荐模式 因此不需要userId 更不需要获取用户模型 主打的就是一个奔放 直接全部随机
        //从推荐服务中获取随机分类信息
        final Set<Integer> integers = new HashSet<>(recommendService.randomRecommend());
        //通过仓储的join 查询出关联内容
        return computeRecommendResult(integers);
    }

    //用于用户进入首页时默认的推荐模式 也就是根据分类大体推荐
    //这里要注意的是 如果用户在开屏中选择了一些分类 那么前端将等到后端返回记录用户模型成功之后才向此接口发送请求
    //这里将对用户身份进行核验 如果处于未登录状态 则直接返回
    //todo 如果之后增加注册成功的选择分类的界面 则这里就要访问这个接口了 不过或许是前端的工作？
    @PostMapping("/rough")
    public Result roughRecommend(){
        //确保用户存在 因为不登陆 是不能获得token的 也就无法存储信息
        if(ObjectUtils.isEmpty(UserHolder.get())){
            return Result.error(ResultMessageConstants.NO_USER_TOKEN);
        }
        //为了程序的健壮性 在service中 即使用户模型中分类不足 抑或是分类为空 的 未曾设想的情况
        //将调用默认的推荐 随机推荐一批
        final Set<Integer> integers = new HashSet<>(recommendService.roughRecommend(UserHolder.get()));
        //同上 有可能出现查询的结果是空的情况 这样也需要进行提示
        return computeRecommendResult(integers);
    }

    private Result computeRecommendResult(Set<Integer> categoryIds) {
//        final List<SubstanceVO> substanceByCategories = substanceService
//                .getSubstanceByCategories(categoryIds, 1,config.getSubstanceNums());
        String redisKeyPre= RedisConstants.REDIS_FIELD_SUBSTANCE+RedisConstants.REDIS_DESC_PRELOAD+":";
        final List<SubstanceVO> substanceByCategories=new ArrayList<>();
        categoryIds.forEach(item->{
            String redisKey=redisKeyPre+item;
            final Set<SubstanceVO> cacheSubstances = substanceService.getCacheSubstances(redisKey, config.getSubstanceNums());
            if(!ObjectUtils.isEmpty(cacheSubstances)){
                substanceByCategories.addAll(cacheSubstances);
            }
        });
        Set<CategoryVO> categorySet=new HashSet<>();
        substanceByCategories.forEach(item->{
            CategoryVO categoryVO=new CategoryVO();
            categoryVO.setId(item.getCategoryId());
            categoryVO.setName(item.getCategoryName());
            final CategoryVO byId = CategoryVOHolder.getById(item.getCategoryId());
            if(byId==null){
                categoryVO.setDescription("没有关于此分类的介绍");
            }else {
                categoryVO.setDescription(byId.getDescription());
            }
            categorySet.add(categoryVO);
        });
        String msg= ResultMessageConstants.RECOMMEND_NEW_SUBSTANCES;
        if(ObjectUtils.isEmpty(substanceByCategories)){
            msg= ResultMessageConstants.RECOMMEND_EMPTY;
        }
        Pair<List<SubstanceVO>,Set<CategoryVO>> result=new Pair<>(substanceByCategories,categorySet);
        return Result.ok().msg(msg).data(result);
    }

    //嗯 或许是vip的专利？ 根据浏览记录来确定推荐
    //todo 之后改造成vip功能 这样的话 需要添加AOP或者是Spring的安全模块来进行检验了
    @PostMapping("/label")
    public Result labelRecommend(){
        return Result.ok();
    }
}
